@file:UnTested

package com.basic.ui.view

import android.graphics.*
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.view.View
import android.view.ViewOutlineProvider
import androidx.annotation.ColorInt
import com.basic.ui.R
import com.basic.ui.UnTested

/**
 *
 * 减少 shape xml 文件的创建
 *
 * @author Peter Liu
 * @since 2023/7/12 00:10
 *
 */

sealed class Shape(@ColorInt solideColor: Int = Color.TRANSPARENT) {

    protected var gradientDrawable: GradientDrawable = GradientDrawable().apply {
        setColor(solideColor)
    }

    fun setCornerRadius(radius: Float): Shape {
        gradientDrawable.cornerRadius = radius
        return this
    }

    @JvmOverloads
    fun setCornerRadius(
        topLeftRadius: Float,
        topRightRadius: Float,
        bottomRightRadius: Float = topRightRadius,
        bottomLeftRadius: Float = topLeftRadius
    ): Shape {
        gradientDrawable.cornerRadii = floatArrayOf(
            topLeftRadius, topLeftRadius,
            topRightRadius, topRightRadius,
            bottomRightRadius, bottomRightRadius,
            bottomLeftRadius, bottomLeftRadius,
        )
        return this
    }

    fun setStroke(width: Int, @ColorInt color: Int): Shape {
        gradientDrawable.setStroke(width, color)
        return this
    }

    fun setGradientColors(
        colors: IntArray?,
        orientation: GradientDrawable.Orientation = GradientDrawable.Orientation.LEFT_RIGHT
    ): Shape {
        if (colors?.size == 1) {
            gradientDrawable.setColor(colors[0])
        } else {
            gradientDrawable.colors = colors
            gradientDrawable.orientation = orientation
        }
        return this
    }

    fun getDrawable(): Drawable {
        return gradientDrawable
    }
}

class RectShape(@ColorInt solideColor: Int = Color.TRANSPARENT) : Shape(solideColor) {
    init {
        this.gradientDrawable.shape = GradientDrawable.RECTANGLE
    }
}

class LineShape(@ColorInt solideColor: Int = Color.TRANSPARENT) : Shape(solideColor) {
    init {
        gradientDrawable.shape = GradientDrawable.LINE
    }
}

class OvalShape(@ColorInt solideColor: Int = Color.TRANSPARENT) : Shape(solideColor) {
    init {
        gradientDrawable.shape = GradientDrawable.OVAL
    }
}

class RingShape(@ColorInt solideColor: Int = Color.TRANSPARENT) : Shape(solideColor) {
    init {
        gradientDrawable.shape = GradientDrawable.RING
    }
}

var View.shape: Shape?
    get() {
        return getTag(R.id.shape) as? Shape
    }
    set(value) {
        setTag(R.id.shape, value)
        if (value != null) {
            background = value.getDrawable()
        }
    }

val View.backgroudColor: Int
    @ColorInt get() = (background as? ColorDrawable)?.color ?: Color.TRANSPARENT

fun View.setCornerRadius(
    topLeftRadius: Float,
    topRightRadius: Float = topLeftRadius,
    bottomRightRadius: Float = topRightRadius,
    bottomLeftRadius: Float = topLeftRadius
): View {
    when (background) {
        null, is ColorDrawable-> {
            shape = RectShape(backgroudColor).setCornerRadius(
                topLeftRadius,
                topRightRadius,
                bottomRightRadius,
                bottomLeftRadius
            )
        }
        this.shape?.getDrawable() -> {
            //不mutate, 复用shape的drawable
            shape!!.setCornerRadius(
                topLeftRadius,
                topRightRadius,
                bottomRightRadius,
                bottomLeftRadius
            )
        }
        else -> { //may be bitmap,
            val outlineProvider = RadiusViewOutlineProvider()
            outlineProvider.setCornerRadius(
                topLeftRadius,
                topRightRadius,
                bottomRightRadius,
                bottomLeftRadius
            )
            clipToOutline = true
        }
    }
    return this
}

fun View.setStroke(width: Int, @ColorInt color: Int): View {
    when (background) {
        null, is ColorDrawable-> {
            shape = RectShape(backgroudColor).setStroke(width, color)
        }
        this.shape?.getDrawable() -> {
            //不mutate, 复用shape的drawable
            shape!!.setStroke(width, color)
        }
        else -> { //may be bitmap,

        }
    }
    return this
}

fun View.setGradientColors(
    colors: IntArray?,
    orientation: GradientDrawable.Orientation = GradientDrawable.Orientation.LEFT_RIGHT
) {
    when (background) {
        null -> {
            shape = RectShape().setGradientColors(colors, orientation)
        }
        this.shape?.getDrawable() -> {
            //不mutate, 复用shape的drawable
            shape!!.setGradientColors(colors, orientation)
        }
        else -> {
            //may be bitmap, do nothing
        }
    }
}

internal class RadiusViewOutlineProvider() : ViewOutlineProvider() {
    private var radius: Float? = null
    private var cornerRadii: FloatArray? = null

    fun setCornerRadius(radius: Float) {
        this.radius = radius
    }

    fun setCornerRadius(
        topLeftRadius: Float,
        topRightRadius: Float = topLeftRadius,
        bottomRightRadius: Float = topRightRadius,
        bottomLeftRadius: Float = topLeftRadius
    ) {
        cornerRadii = floatArrayOf(
            topLeftRadius, topLeftRadius,
            topRightRadius, topRightRadius,
            bottomRightRadius, bottomRightRadius,
            bottomLeftRadius, bottomLeftRadius,
        )
    }

    override fun getOutline(view: View?, outline: Outline) {
        val background = view!!.background
        val rect: Rect
        outline.alpha = 0.0f
        if (background != null) {
            rect = background.bounds
        } else {
            rect = Rect(0, 0, view.width, view.height)
            outline.alpha = 0.0f
        }
        if (radius != null) {
            outline.setRoundRect(rect, radius!!)
        } else if (cornerRadii != null) {
            val path = Path()
            path.addRoundRect(RectF(rect), cornerRadii!!, Path.Direction.CW)
            outline.setConvexPath(path)
        }
    }
}



